import router from "@/router";
import {
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError,
  AxiosInstance,
} from "axios";
import AxiosHeaders from "axios";
import { encodeParam } from "./encrypt";
import NProgress from "nprogress";
import "nprogress/nprogress.css";

interface newConfig extends AxiosRequestConfig {
  // 设置重复请求次数
  retry?: number;
  // 请求次数
  __retryCount?: number;
}
NProgress.configure({ showSpinner: false });
// 创建axios实例
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_API_BASE_URL,
  timeout: 10000,
});

let loading = true;
let requestNum = 0;
let loadingInstance: any | null = null;
export const addLoading = () => {
  const htmlClass = document.documentElement.classList.value;
  // 增加loading 如果pending请求数量等于1，弹出loading, 防止重复弹出
  requestNum++;
  if (requestNum == 1) {
    loadingInstance = ElLoading.service({
      text: "加载中...",
      background:
        htmlClass == "dark" ? "rgba(0, 0, 0, 0.8)" : "rgba(255, 255, 255, 0.8)",
    });
  }
};

export const cancelLoading = () => {
  // 取消loading 如果pending请求数量等于0，关闭loading
  requestNum--;
  if (requestNum === 0) loadingInstance?.close();
};

// 请求拦截
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    NProgress.start();
    if (config.url !== "/account/login" && localStorage.getItem("authInfo")) {
      const { token } = JSON.parse(localStorage.getItem("authInfo")!);
      config.headers!.Authorization = token;
    }

    if (!config.headers!.noLoading) {
      addLoading();
      cancelLoading();
    }
    return config;
  },
  (err: AxiosError<any, any>) => {
    if (loading) cancelLoading();
    return Promise.reject(err);
  }
);

// 响应拦截
service.interceptors.response.use(
  (response: AxiosResponse) => {
    NProgress.done();
    if (loading) cancelLoading();
    const { status, data } = response;
    const { url } = response.config;
    if (status == 200) return data;
    else if (status == 401 || status == 403) {
      router.replace(`/login?redirect=${encodeParam(url)}`);
    } else {
      ElMessage.error(data.message || "网络连接异常");
      return Promise.reject(data.message || new Error("网络连接异常"));
    }
  },
  async (error: AxiosError<any, any> & newConfig) => {
    if (loading) cancelLoading();

    requestAgainSend(error, service);
    // const { url } = error.config as AxiosRequestConfig;
    const { data } = error.response as AxiosRequestConfig;
    if (error.response) {
      if (
        error.response.status === 401 ||
        error.response.status === 403 ||
        data?.message?.indexOf("请重新登录") != -1
      ) {
        localStorage.clear();
        router.replace(
          `/login?redirect=${encodeParam(window.location.pathname)}`
        );
      }
    }
    const { retry, __retryCount } = error.config as any;
    if (error.message.indexOf("timeout") !== -1 || retry == __retryCount) {
      ElMessage.error(data?.message || "请求超时!请您稍后重试");
    }

    return Promise.reject(error);
  }
);

class request {
  static get<T>(url: string, paramObj: {} = {}, option?: any): Promise<T> {
    return service.get(url, { params: paramObj, ...option });
  }
  static post<T>(url: string, params: {} = {}, option?: any): Promise<T> {
    return service.post(url, params, option);
  }
  static put<T>(url: string, params: {} = {}, option?: any): Promise<T> {
    return service.put(url, params, option);
  }
  static delete<T>(url: string, params: string): Promise<T> {
    return service.delete(`${url}/${params}`);
  }
}

// 判断一个字符串是否为JSON字符串
export let isJsonStr = (str: string) => {
  if (typeof str == "string") {
    try {
      var obj = JSON.parse(str);
      if (typeof obj == "object" && obj) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  }
};

// 请求重试
async function requestAgainSend(
  err: AxiosError<any, any> & newConfig,
  axios: AxiosInstance
) {
  let config = err.config as any;
  // config.retry 具体接口配置的重发次数
  if (!config || !config.retry) return Promise.reject(err);
  console.log(config);

  // 设置用于记录重试计数的变量 默认为0
  config.__retryCount = config.__retryCount || 0;

  // 判断是否超过了重试次数
  if (config.__retryCount >= config.retry) {
    return Promise.reject(err);
  }
  // 重试次数
  config.__retryCount += 1;

  // 延时处理
  var backoff = new Promise(function (resolve) {
    setTimeout(function () {
      resolve("");
    }, config.retryDelay || 1000);
  });
  // 重新发起axios请求
  return backoff.then(function () {
    // 判断是否是JSON字符串
    // TODO: 未确认config.data再重发时变为字符串的原因
    if (config.data && isJsonStr(config.data)) {
      config.data = JSON.parse(config.data);
    }
    // debugger;
    config.headers = AxiosHeaders(config.headers);
    return axios(config);
  });
}

export default request;
